package com.zc.handler;

import com.zc.enums.OrderStatusChangeEventEnum;
import com.zc.enums.OrderStatusEnum;
import org.springframework.messaging.Message;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.access.StateMachineAccess;
import org.springframework.statemachine.listener.AbstractCompositeListener;
import org.springframework.statemachine.state.State;
import org.springframework.statemachine.support.DefaultStateMachineContext;
import org.springframework.statemachine.support.LifecycleObjectSupport;
import org.springframework.statemachine.support.StateMachineInterceptorAdapter;
import org.springframework.statemachine.transition.Transition;
import org.springframework.util.Assert;

import java.util.Iterator;
import java.util.List;

/**
 * @author : ville
 * @version : 1.0.0
 * @description : 持久化状态机处理器
 * @createTime : 2020/6/9-17:08
 * @copyright : villebo@126.com
 * @modify : ville
 **/
public class PersistStateMachineHandler extends LifecycleObjectSupport {

    private final StateMachine<OrderStatusEnum, OrderStatusChangeEventEnum> stateMachine;

    private final PersistingStateChangeInterceptor interceptor = new PersistingStateChangeInterceptor();

    private final CompositePersistStateChangeListener listeners = new CompositePersistStateChangeListener();

    /**
     * 实例化一个新的持久化状态机Handler
     *
     * @param stateMachine 状态机实例
     */
    public PersistStateMachineHandler(StateMachine<OrderStatusEnum, OrderStatusChangeEventEnum> stateMachine) {
        Assert.notNull(stateMachine, "State machine must be set");
        this.stateMachine = stateMachine;
    }

    @Override
    protected void onInit() throws Exception {
        stateMachine.getStateMachineAccessor().doWithAllRegions(p -> p.addStateMachineInterceptor(interceptor));
    }


    /**
     * 处理entity的事件
     *
     * @param event
     * @param state
     * @return 如果事件被接受处理，返回true
     */
    public boolean handleEventWithState(Message<OrderStatusChangeEventEnum> event,
                                        OrderStatusEnum state) {
        stateMachine.stop();
        List<StateMachineAccess<OrderStatusEnum, OrderStatusChangeEventEnum>> withAllRegions =
                stateMachine.getStateMachineAccessor().withAllRegions();
        withAllRegions.forEach(p -> p.resetStateMachine(new DefaultStateMachineContext<>(state,
                null, null, null)));
        stateMachine.start();
        return stateMachine.sendEvent(event);
    }

    /**
     * 添加listener
     *
     * @param listener the listener
     */
    public void addPersistStateChangeListener(PersistStateChangeListener listener) {
        listeners.register(listener);
    }


    /**
     * 可以通过 addPersistStateChangeListener，增加当前Handler的PersistStateChangeListener。
     * 在状态变化的持久化触发时，会调用相应的实现了PersistStateChangeListener的Listener实例。
     */
    public interface PersistStateChangeListener {

        /**
         * 当状态被持久化，调用此方法
         *
         * @param state
         * @param message
         * @param transition
         * @param stateMachine 状态机实例
         */
        void onPersist(State<OrderStatusEnum, OrderStatusChangeEventEnum> state,
                       Message<OrderStatusChangeEventEnum> message, Transition<OrderStatusEnum,
                OrderStatusChangeEventEnum> transition,
                       StateMachine<OrderStatusEnum, OrderStatusChangeEventEnum> stateMachine);
    }

    /**
     * 状态拦截器
     */
    private  class PersistingStateChangeInterceptor extends StateMachineInterceptorAdapter<OrderStatusEnum, OrderStatusChangeEventEnum> {
        /**
         * 状态预处理的拦截器方法
         * @param state
         * @param message
         * @param transition
         * @param stateMachine
         */
        @Override
        public void preStateChange(State<OrderStatusEnum, OrderStatusChangeEventEnum> state,
                                   Message<OrderStatusChangeEventEnum> message,
                                   Transition<OrderStatusEnum, OrderStatusChangeEventEnum> transition,
                                   StateMachine<OrderStatusEnum,
                OrderStatusChangeEventEnum> stateMachine) {
            listeners.onPersist(state, message, transition, stateMachine);
        }
    }

    private static class CompositePersistStateChangeListener extends AbstractCompositeListener<PersistStateChangeListener> implements
            PersistStateChangeListener {

        @Override
        public void onPersist(State<OrderStatusEnum, OrderStatusChangeEventEnum> state,
                              Message<OrderStatusChangeEventEnum> message,
                              Transition<OrderStatusEnum, OrderStatusChangeEventEnum> transition,
                              StateMachine<OrderStatusEnum,
                OrderStatusChangeEventEnum> stateMachine) {
            Iterator<PersistStateChangeListener> iterator = getListeners().reverse();
            while (iterator.hasNext()) {
                PersistStateChangeListener listener = iterator.next();
                listener.onPersist(state, message, transition, stateMachine);
            }
        }
    }
}
